<script setup lang="ts">
  import { ref, onMounted, watch } from 'vue'
  import { useElementSize, useParentElement } from '@vueuse/core'
  import { ElUtil } from '../../utils'
  import { ContactPropsType } from './types'
  import { ContactStrategyConst } from './consts'

  defineOptions({
    name: 'SContact'
  })

  const props = withDefaults(defineProps<ContactPropsType>(), {
    strategy: ContactStrategyConst.Prev,
    contact: [] as any,
    restore: [] as any
  })

  const SContactRef = ref<HTMLElement>()
  // 当前组件根元素父元素的宽度
  const { width: parentWidth } = useElementSize(useParentElement(SContactRef))
  // 记录当前组件根元素与前(后)一个元素是第几次接触
  const contactCnt = ref(0)
  // 当前组件根元素与前(后)一个元素每次接触与相应的恢复处理函数的映射
  const contactCntRestoreMap = ref<Record<number, { parentWidth: number; restore: () => void }>>({})
  // 判断是否需要处理当前组件根元素与前(后)一个元素接触
  const isHandleContact = () => {
    if (props.strategy === ContactStrategyConst.Prev) {
      return ElUtil.isContactPrevious(SContactRef) && contactCnt.value < props.contact.length
    } else {
      return ElUtil.isContactNext(SContactRef) && contactCnt.value < props.contact.length
    }
  }
  // 处理当前组件根元素与前(后)一个元素接触
  const handleContact = () => {
    contactCnt.value++
    contactCntRestoreMap.value[contactCnt.value] = {
      parentWidth: parentWidth.value || ElUtil.getParentChildrenWidth(SContactRef).widthSum,
      restore: props.restore[contactCnt.value - 1] || (() => {})
    }
    props.contact[contactCnt.value - 1]?.()
  }
  onMounted(() => {
    while (isHandleContact()) handleContact()
  })
  watch(
    () => parentWidth.value,
    () => {
      // 如果当前组件根元素与前一个元素接触，且还有相应的 contact 处理函数未执行
      if (isHandleContact()) handleContact()
      // 根据当前组件根元素与前一个元素第几次接触，逆序遍历
      const contactCntRestoreMapKeys = Object.keys(contactCntRestoreMap.value).sort(
        (a, b) => Number(b) - Number(a)
      )
      for (const key of contactCntRestoreMapKeys) {
        // 当前组件根元素父元素的宽度大于此次遍历到的 contactCntRestoreMap 中记录的宽度，且还有相应的 restore 处理
        // 函数未执行
        if (
          parentWidth.value > contactCntRestoreMap.value[Number(key)].parentWidth &&
          contactCnt.value > 0
        ) {
          contactCnt.value--
          contactCntRestoreMap.value[Number(key)].restore()
          Reflect.deleteProperty(contactCntRestoreMap.value, key)
        }
      }
    }
  )
</script>

<template>
  <div class="s-contact" ref="SContactRef">
    <slot />
  </div>
</template>

<style lang="scss">
  @use './style' as *;
</style>
